package br.ufc.quixada.adrs.service;

import br.ufc.quixada.adrs.dao.UsuarioDAO;
import br.ufc.quixada.adrs.model.Perfil;
import br.ufc.quixada.adrs.model.Usuario;
import br.ufc.quixada.adrs.util.Msg;
import br.ufc.quixada.adrs.util.UtilAdrs;
import java.sql.SQLException;
import java.util.List;
import org.slf4j.LoggerFactory;

public class UsuarioService {

    private final UsuarioDAO usuarioDAO = new UsuarioDAO();

    public boolean insertUsuario(Usuario usuario) {
        try {
            UtilAdrs.upperCase(usuario);
            usuarioDAO.insert(usuario);
            return true;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return false;
        }
    }

    public boolean updateUsuario(Usuario usuario) {
        try {
            UtilAdrs.upperCase(usuario);
            usuarioDAO.update(usuario);
            return true;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return false;
        }
    }

    public boolean deleteUsuario(Usuario usuario) {
        try {
            usuarioDAO.delete(usuario);
            return true;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return false;
        }
    }

    public Usuario getUsuarioById(Long id) {
        try {
            Usuario user = usuarioDAO.getById(id);
            return user;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public Usuario getUsuarioByAdrsId(Long id) {
        try {
            Usuario user = usuarioDAO.getByAdrsId(id);
            return user;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public Perfil validarUsuario(Usuario usuarioEntrada, String conta) {
        Usuario user = getUsuarioByLogin(usuarioEntrada.getLogin());
        if (user != null) {
            Perfil perfil = null;
            if (conta.trim().equals("visit")) {
                VisitanteService service = new VisitanteService();
                perfil = service.getVisitanteByUsuarioId(user.getId());
            } else if (conta.trim().equals("adrs")) {
                AdrsService service = new AdrsService();
                perfil = service.getAdrsByUsuarioId(user.getId());
            } else if (conta.trim().equals("admin")) {
                AdministradorService service = new AdministradorService();
                perfil = service.getAdministradorByUsuarioId(user.getId());
            } else if (conta.trim().equals("supervisor")) {
                SupervisorService service = new SupervisorService();
                perfil = service.getSupervisorByUsuarioId(user.getId());
            } else if (conta.trim().equals("auto")) {
                VisitanteService service = new VisitanteService();
                perfil = service.getVisitanteByUsuarioId(user.getId());
                if (perfil == null) {
                    AdrsService adrsS = new AdrsService();
                    perfil = adrsS.getAdrsByUsuarioId(user.getId());
                    if (perfil == null) {
                        AdministradorService adminS = new AdministradorService();
                        perfil = adminS.getAdministradorByUsuarioId(user.getId());
                    }
                }
            }
            if (perfil != null) {
                perfil.setUsuario(user);
                if (perfil.getUsuario().validaSenha(usuarioEntrada.getSenha())) {
                    return perfil;
                }
            }
        }
        return null;
    }

    public Usuario getUsuarioByLogin(String login) {
        try {
            Usuario user = usuarioDAO.getByLogin(login);
            return user;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public List<Usuario> getUsuariosByNome(String nome) {
        try {
            List<Usuario> users = usuarioDAO.getByNome(nome);
            return users;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public Usuario getUsuarioByEmail(String email) {
        try {
            Usuario user = usuarioDAO.getByEmail(email);
            return user;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public Usuario getUsuarioByCpf(String cpf) {
        try {
            Usuario user = usuarioDAO.getByCpf(cpf);
            return user;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public Usuario getUsuarioByRg(String rg) {
        try {
            Usuario user = usuarioDAO.getByRg(rg);
            return user;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public List<Usuario> getAllUsuarios() {
        try {
            List<Usuario> users = usuarioDAO.getAll();
            return users;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public String validaParaInsercao(Usuario u) {
        if (!validaCPF(u.getCpf())) {
            return Msg.INPUT_ERROR_INVALID_CPF;
        }

        if (getUsuarioByCpf(u.getCpf()) != null) {
            return Msg.EXISTANT_CPF;
        }
        if (getUsuarioByEmail(u.getEmail()) != null) {
            return Msg.EXISTANT_EMAIL;
        }
        if (getUsuarioByLogin(u.getLogin()) != null) {
            return Msg.EXISTANT_LOGIN;
        }
        if (getUsuarioByRg(u.getRg()) != null) {
            return Msg.EXISTANT_RG;
        }

        //deve ser o ultimo ou irá mascarar os outros no produtorService
        if (u.getEmail() == null || u.getEmail().isEmpty()) {
            return Msg.REQUIRED_EMAIL_FIELD;
        }
        if (verificaEmailInvalido(u.getEmail())) {
            return Msg.INPUT_ERROR_INVALID_EMAIL;
        }
        return Msg.OK;
    }

    public String validaParaEdicao(Usuario user) {
        Usuario u = null;

        if (!validaCPF(user.getCpf())) {
            return Msg.INPUT_ERROR_INVALID_CPF;
        }

        u = getUsuarioByCpf(user.getCpf());
        if (u != null && !u.getId().equals(user.getId())) {
            return Msg.EXISTANT_CPF;
        } else {
            u = null;
        }
        u = getUsuarioByEmail(user.getEmail());
        if (u != null && !u.getId().equals(user.getId())) {
            return Msg.EXISTANT_EMAIL;
        } else {
            u = null;
        }
        u = getUsuarioByLogin(user.getLogin());
        if (u != null && !u.getId().equals(user.getId())) {
            return Msg.EXISTANT_LOGIN;
        } else {
            u = null;
        }
        u = getUsuarioByRg(user.getRg());
        if (u != null && !u.getId().equals(user.getId())) {
            return Msg.EXISTANT_RG;
        } else {
            u = null;
        }

        //deve ser o ultimo ou irá mascarar os outros no produtorService
        if (user.getEmail() == null || user.getEmail().isEmpty()) {
            return Msg.REQUIRED_EMAIL_FIELD;
        }
        if (verificaEmailInvalido(user.getEmail())) {
            return Msg.INPUT_ERROR_INVALID_EMAIL;
        }
        return Msg.OK;
    }

    public boolean verificaEmailInvalido(String email) {
        if (!email.toUpperCase().matches(Msg.EMAIL_REGEX)) {
            return true;
        }
        return false;
    }

    public boolean validaCPF(String strCpf) {
        strCpf = UtilAdrs.desFormataCPF(strCpf);
        int d1, d2;
        int digito1, digito2, resto;
        int digitoCPF;
        String nDigResult;

        d1 = d2 = 0;
        digito1 = digito2 = resto = 0;

        for (int nCount = 1; nCount < strCpf.length() - 1; nCount++) {
            digitoCPF = Integer.valueOf(strCpf.substring(nCount - 1, nCount)).intValue();

            //multiplique a ultima casa por 2 a seguinte por 3 a seguinte por 4 e assim por diante.
            d1 = d1 + (11 - nCount) * digitoCPF;

            //para o segundo digito repita o procedimento incluindo o primeiro digito calculado no passo anterior.
            d2 = d2 + (12 - nCount) * digitoCPF;
        }

        //Primeiro resto da divisão por 11.
        resto = (d1 % 11);

        //Se o resultado for 0 ou 1 o digito é 0 caso contrário o digito é 11 menos o resultado anterior.
        if (resto < 2) {
            digito1 = 0;
        } else {
            digito1 = 11 - resto;
        }

        d2 += 2 * digito1;

        //Segundo resto da divisão por 11.
        resto = (d2 % 11);

        //Se o resultado for 0 ou 1 o digito é 0 caso contrário o digito é 11 menos o resultado anterior.
        if (resto < 2) {
            digito2 = 0;
        } else {
            digito2 = 11 - resto;
        }

        //Digito verificador do CPF que está sendo validado.
        String nDigVerific = strCpf.substring(strCpf.length() - 2, strCpf.length());

        //Concatenando o primeiro resto com o segundo.
        nDigResult = String.valueOf(digito1) + String.valueOf(digito2);

        //comparar o digito verificador do cpf com o primeiro resto + o segundo resto.
        return nDigVerific.equals(nDigResult);
    }
}
